#include "JackControl.h";
#include <jack/jack.h>
#include <jack/types.h>
#include <iostream>

using std::cout;using std::cin;using std::endl;using std::cerr;

jack_port_t *input_port1;
jack_port_t *input_port2;
jack_port_t *input_port3;
jack_port_t *input_port4;
jack_nframes_t frames;

jack_default_audio_sample_t *in1;
jack_default_audio_sample_t *in2;
jack_default_audio_sample_t *in3;
jack_default_audio_sample_t *in4;

/**
 * The process callback for this JACK application is called in a
 * special realtime thread once for each audio cycle.
 *
 * This client does nothing more than copy data from its input
 * port to its output port. It will exit when stopped by
 * the user (e.g. using Ctrl-C on a unix-ish operating system)
 */
int process (jack_nframes_t nframes, void *arg)
{
        frames = nframes;
        in1 = (jack_default_audio_sample_t*)jack_port_get_buffer (input_port1, nframes);
        in2 = (jack_default_audio_sample_t*)jack_port_get_buffer (input_port2, nframes);
        in3 = (jack_default_audio_sample_t*)jack_port_get_buffer (input_port3, nframes);
        in4 = (jack_default_audio_sample_t*)jack_port_get_buffer (input_port4, nframes);

        /*
        cout << "[";
        for(int i=0;i<nframes;i++) {
            cout << in2[i] << ",";
        }
        cout << "]" << endl;
        */

        return 0;
}

JackControl::JackControl()
{
    const char **ports;
    const char *client_name = "HyperTerrain";
    const char *server_name = NULL;
    jack_options_t options = JackNullOption;
    jack_status_t status;

    /* open a client connection to the JACK server */
    /* open a client connection to the JACK server */

    client = jack_client_open (client_name, options, &status, server_name);
    if (client == NULL) {
            cerr << "jack_client_open() failed,status = 0x%2.0x" << endl;
            if (status & JackServerFailed) {
                    cerr << "Unable to connect to JACK server" << endl;
            }
            exit (1);
    }
    if (status & JackServerStarted) {
            cout << "JACK server started" << endl;
    }
    if (status & JackNameNotUnique) {
            client_name = jack_get_client_name(client);
            cout <<  "unique name `%s' assigned" << endl;
    }

    input_port1 = jack_port_register (client, "in1",JACK_DEFAULT_AUDIO_TYPE,JackPortIsInput, 0);
    input_port2 = jack_port_register (client, "in2",JACK_DEFAULT_AUDIO_TYPE,JackPortIsInput, 0);
    input_port3 = jack_port_register (client, "in3",JACK_DEFAULT_AUDIO_TYPE,JackPortIsInput, 0);
    input_port4 = jack_port_register (client, "in4",JACK_DEFAULT_AUDIO_TYPE,JackPortIsInput, 0);

    /* tell the JACK server to call `process()' whenever
       there is work to be done.
    */
    //jack_set_process_callback (client, process, 0);

    if (jack_activate (client)) {
            cerr << "cannot activate client" << endl;
            exit (1);
    }

    frames = jack_get_buffer_size(client);

    jackConnect("scsynth:out6","HyperTerrain:in1");
    jackConnect("scsynth:out7","HyperTerrain:in2");
    jackConnect("scsynth:out8","HyperTerrain:in3");
    jackConnect("scsynth:out5","HyperTerrain:in4");

    cout<< "=============================================="<<endl;
    cout << "These are the current server ports:"<<endl;
    getServerPorts();
}

void JackControl::getServerPorts() {
    const char **ports = jack_get_ports(client,NULL,NULL,0);
    int i=0;
    while(ports[i]!=NULL) {
        cout<< "=============================================="<<endl;
        cout << "Port "<<i<<": "<<endl << ports[i] <<endl;
        i++;
    }
}

void JackControl::getServerInputPorts() {
    const char **ports = jack_get_ports(client,NULL,NULL,0x2);
    int i=0;
    while(ports[i]!=NULL) {
        cout<< "=============================================="<<endl;
        cout << "Port "<<i<<": "<<endl << ports[i] <<endl;
        i++;
    }
}

void JackControl::getServerOutPorts() {
    const char **ports = jack_get_ports(client,NULL,NULL,0x1);
    int i=0;
    while(ports[i]!=NULL) {
        cout<< "=============================================="<<endl;
        cout << "Port "<<i<<": "<<endl << ports[i] <<endl;
        i++;
    }
}

int JackControl::jackConnect(const char* port1,const char* port2) {
    if(jack_connect(client,port1,port2) == 0) {
        cout<< "=============================================="<<endl;
        cout << "Succesfully connected " << port1 << " with " << port2 <<"."<<endl;
    } else {
        cout<< "=============================================="<<endl;
        cerr << "Could not connect " << port1 << " with " << port2 <<"."<<endl;
        //cerr << "This may be due to the fact that it is already connected"<<endl;
    }
}

int JackControl::jackDisconnect(const char* port1,const char* port2) {
    if(jack_disconnect(client,port1,port2) == 0) {
        cout<< "=============================================="<<endl;
        cout << "Succesfully disconnected " << port1 << " with " << port2 <<"."<<endl;
    } else {
        cout<< "=============================================="<<endl;
        cerr << "Could not disconnect " << port1 << " with " << port2 <<"."<<endl;
    }
}

float* JackControl::getInput1()
{
    //return in1;
    return (jack_default_audio_sample_t*)jack_port_get_buffer (input_port1, frames);
}

float* JackControl::getInput2()
{
    //return in2;
    return (jack_default_audio_sample_t*)jack_port_get_buffer (input_port2, frames);
}

float* JackControl::getInput3()
{
    //return in3;
    return (jack_default_audio_sample_t*)jack_port_get_buffer (input_port3, frames);
}

float* JackControl::getInput4()
{
    //return in4;
    return (jack_default_audio_sample_t*)jack_port_get_buffer (input_port4, frames);
}

int JackControl::getFrames()
{
    return frames;
}
